//===================================================================================
// Microsoft patterns & practices
// Composite Application Guidance for Windows Presentation Foundation and Silverlight
//===================================================================================
// Copyright (c) Microsoft Corporation.  All rights reserved.
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE.
//===================================================================================
// The example companies, organizations, products, domain names,
// e-mail addresses, logos, people, places, and events depicted
// herein are fictitious.  No association with any real company,
// organization, product, domain name, email address, logo, person,
// places, or events is intended or should be inferred.
//===================================================================================
using System;
using System.Windows.Input;
using Windows.UI.Xaml.Controls;

namespace Microsoft.Practices.Prism.Commands
{
	/// <summary>
	/// Base behavior to handle connecting a <see cref="Control"/> to a Command.
	/// </summary>
	/// <typeparam name="T">The target object must derive from Control</typeparam>
	/// <remarks>
	/// CommandBehaviorBase can be used to provide new behaviors for commands.
	/// </remarks>
	public class CommandBehaviorBase<T> where T : Control
	{
		private ICommand command;
		private object commandParameter;
		private readonly WeakReference targetObject;
		private readonly EventHandler commandCanExecuteChangedHandler;

		/// <summary>
		/// Constructor specifying the target object.
		/// </summary>
		/// <param name="targetObject">The target object the behavior is attached to.</param>
		public CommandBehaviorBase(T targetObject)
		{
			this.targetObject = new WeakReference(targetObject);

			// In Silverlight, unlike WPF, this is strictly not necessary since the Command properties
			// in Silverlight do not expect their CanExecuteChanged handlers to be weakly held,
			// but holding on to them in this manner should do no harm.
			this.commandCanExecuteChangedHandler = new EventHandler(this.CommandCanExecuteChanged);
		}

		/// <summary>
		/// Corresponding command to be execute and monitored for <see cref="ICommand.CanExecuteChanged"/>
		/// </summary>
		public ICommand Command
		{
			get { return command; }
			set
			{
				if (this.command != null)
				{
					this.command.CanExecuteChanged -= this.commandCanExecuteChangedHandler;
				}

				this.command = value;
				if (this.command != null)
				{
					this.command.CanExecuteChanged += this.commandCanExecuteChangedHandler;
					UpdateEnabledState();
				}
			}
		}

		/// <summary>
		/// The parameter to supply the command during execution
		/// </summary>
		public object CommandParameter
		{
			get { return this.commandParameter; }
			set
			{
				if (this.commandParameter != value)
				{
					this.commandParameter = value;
					this.UpdateEnabledState();
				}
			}
		}

		/// <summary>
		/// Object to which this behavior is attached.
		/// </summary>
		protected T TargetObject
		{
			get
			{
				return targetObject.Target as T;
			}
		}

		/// <summary>
		/// Updates the target object's IsEnabled property based on the commands ability to execute.
		/// </summary>
		protected virtual void UpdateEnabledState()
		{
			if (TargetObject == null)
			{
				this.Command = null;
				this.CommandParameter = null;
			}
			else if (this.Command != null)
			{
				TargetObject.IsEnabled = this.Command.CanExecute(this.CommandParameter);
			}
		}

		private void CommandCanExecuteChanged(object sender, EventArgs e)
		{
			this.UpdateEnabledState();
		}

		/// <summary>
		/// Executes the command, if it's set, providing the <see cref="CommandParameter"/>
		/// </summary>
		protected virtual void ExecuteCommand()
		{
			if (this.Command != null)
			{
				this.Command.Execute(this.CommandParameter);
			}
		}
	}
}